package com.wy.system.filter;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wy.common.result.Result;
import com.wy.common.result.ResultCodeEnum;
import com.wy.common.utils.JwtHelper;
import com.wy.common.utils.ResponseUtil;
import com.wy.model.vo.LoginVo;
import com.wy.system.custom.CustomUser;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 登录过滤器，继承UsernamePasswordAuthenticationFilter，对用户名密码进行登录校验
 */
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
  private RedisTemplate redisTemplate;

  //构造
  public TokenLoginFilter(AuthenticationManager authenticationManager,RedisTemplate redisTemplate) {
    this.setAuthenticationManager(authenticationManager);
    this.setPostOnly(false);
    //指定登录接口及提交方式，可以指定任意路径
    this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/system/index/login","POST"));
    this.redisTemplate = redisTemplate;
  }

  //获取用户名和密码，认证
  public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    try {
      LoginVo loginVo = new ObjectMapper().readValue(request.getInputStream(), LoginVo.class);
      Authentication authenticationToken = new UsernamePasswordAuthenticationToken(loginVo.getUsername(), loginVo.getPassword());
      Authentication authenticate = this.getAuthenticationManager().authenticate(authenticationToken);
      return authenticate;
    } catch (IOException e) {
      e.printStackTrace();
    }
    return null;
  }

  //认证成功调用
  protected void successfulAuthentication(HttpServletRequest request,
                                          HttpServletResponse response,
                                          FilterChain chain,
                                          Authentication auth) throws IOException, ServletException {
    //获取认证对象
    CustomUser customUser = (CustomUser) auth.getPrincipal();
    //保存权限数据
    redisTemplate.opsForValue().set(customUser.getUsername(),
        JSON.toJSONString(customUser.getAuthorities()));
    //生成token
    String token = JwtHelper.createToken(customUser.getUser().getId(),
                    customUser.getUser().getUsername());
    //返回
    Map<String,Object> map = new HashMap<>();
    map.put("token",token);
    ResponseUtil.out(response, Result.ok(map));
  }

  //认证失败调用
  @Override
  protected void unsuccessfulAuthentication(HttpServletRequest request,
                                            HttpServletResponse response,
                                            AuthenticationException e) throws IOException, ServletException {
    if(e.getCause() instanceof RuntimeException) {
      ResponseUtil.out(response, Result.build(null, 204, e.getMessage()));
    } else {
      ResponseUtil.out(response, Result.build(null, ResultCodeEnum.LOGIN_MOBLE_ERROR));
    }
  }
}
